Scenario

작성된 클래스를 기반으로 기능을 확장해야 하는 경우, 일반적으로 상속을 이용한다.
하지만, 상속을 사용하지 못하는 클래스(std::vector와 같이 virtual 소멸자가 없는 클래스)가 있으며,
상속을 통한 기능 확장은 단일 책임(SRP)에 따라 수정 사항을 각각 분리하는 원칙에 위배된다.

데커레이터 패턴은 이미 존재하는 타입에 새로운 기능을 추가하면서도 원래 타입의 코드에 수정을
피할 수 있게 해준다.(열림-닫힘 원칙(OCP) 준수됨)
Scenario
struct Shape{
virtual string str() const =0;
};
struct Circle: Shape{
float radius;
explicit Circle(const float radius): radius(radius) {}
void resize(float factor){ radius*=factor; }
string str() const override {
ostringstream oss;
oss<"A circle of radius "<<radius;
return oss.str();
}
};
처음에 도형을 나타내는 클래스(인터페이스) Shape가 존재하고 이를 상속받아,
ColoredShape와 ColoredTransparentShape를 만들었다.

상속받는 기능이 추가되고, 파생클래스에 추가 기능들을 구현하기 위해서 많은 클래스를 작성해야 한다.
따라서 컴포지션을 활용해 기능을 추가한다.
컴포지션: 데커레이터 패턴에서 객체들에 새로운 기능을 확장할 때 사용하는 메커니즘

- 동적 컴포지션
런타임에 동적으로 무언가를 합성할 수 있게 한다.(높은 유연성을 제공)
- 정적 컴포지션
컴파일 시점에 추가기능이 합성되게 한다.
코드 작성 시점에 객체에 대한 정확한 추가 기능 조합이 결정되어야 함